package com.wuyaya.arch.bom.manage;

import com.wuyaya.arch.bom.obj.WuObjectDefinition;
import com.wuyaya.arch.bom.obj.WuProperty;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class WuObjectFactory {
    private static Map<String, WuObjectDefinition> objectDefinitions = new HashMap<>();

    public static void initObjectFactory() {
        try {
            System.out.println("xxxxxxxxxxxxxxddd");
            String path = "com/wuyaya/wob/";
            Enumeration<URL> resources = WuObjectFactory.class.getClassLoader().getResources(path);
            while (resources.hasMoreElements()) {
                URL resource = resources.nextElement();
                if (resource.getProtocol().equals("file")) {
                    File directory = new File(resource.getFile());
                    File[] files = directory.listFiles((dir, name) -> name.endsWith(".xml"));
                    if (files != null) {
                        for (File file : files) {
                            Document doc = parseXmlFile(file);
                            processPackageElements(doc);
                        }
                    }
                } else if (resource.getProtocol().equals("jar")) {
                    String jarPath = resource.getPath().substring(5, resource.getPath().indexOf("!"));
                    JarFile jar = new JarFile(jarPath);
                    Enumeration<JarEntry> entries = jar.entries();
                    while (entries.hasMoreElements()) {
                        JarEntry entry = entries.nextElement();
                        if (entry.getName().startsWith(path) && entry.getName().endsWith(".xml")) {
                            InputStream inputStream = jar.getInputStream(entry);
                            Document doc = parseXmlFile(inputStream);
                            processPackageElements(doc);
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static Document parseXmlFile(File file) throws Exception {
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
        Document doc = dBuilder.parse(file);
        doc.getDocumentElement().normalize();
        return doc;
    }

    private static Document parseXmlFile(InputStream inputStream) throws Exception {
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
        Document doc = dBuilder.parse(inputStream);
        doc.getDocumentElement().normalize();
        return doc;
    }

    private static void processPackageElements(Document doc) {
        NodeList packageList = doc.getElementsByTagName("package");
        for (int i = 0; i < packageList.getLength(); i++) {
            Node packageNode = packageList.item(i);
            if (packageNode.getNodeType() == Node.ELEMENT_NODE) {
                Element packageElement = (Element) packageNode;
                String packageName = packageElement.getAttribute("name");
                processObjectElements(packageElement, packageName);
            }
        }
    }

    private static void processObjectElements(Element packageElement, String packageName) {
        NodeList objectList = packageElement.getElementsByTagName("object");
        for (int j = 0; j < objectList.getLength(); j++) {
            Node objectNode = objectList.item(j);
            if (objectNode.getNodeType() == Node.ELEMENT_NODE) {
                Element objectElement = (Element) objectNode;
                WuObjectDefinition objectDefinition = createObjectDefinition(objectElement, packageName);
                processPropertyElements(objectElement, objectDefinition);
                objectDefinitions.put(packageName + "." + objectDefinition.getName(), objectDefinition);
            }
        }
    }

    private static WuObjectDefinition createObjectDefinition(Element objectElement, String packageName) {
        String objectName = getTextContent(objectElement, "name");
        String label = getTextContent(objectElement, "label");
        String tableName = getTextContent(objectElement, "tableName");
        String objectManager = getTextContent(objectElement, "objectManager");
        String objectKey = getTextContent(objectElement, "objectKey");
        return new WuObjectDefinition(packageName, objectName, label, tableName, objectManager, objectKey);
    }

    private static void processPropertyElements(Element objectElement, WuObjectDefinition objectDefinition) {
        NodeList propertyList = objectElement.getElementsByTagName("property");
        for (int k = 0; k < propertyList.getLength(); k++) {
            Node propertyNode = propertyList.item(k);
            if (propertyNode.getNodeType() == Node.ELEMENT_NODE) {
                Element propertyElement = (Element) propertyNode;
                WuProperty property = createProperty(propertyElement);
                objectDefinition.addProperty(property);
            }
        }
    }

    private static WuProperty createProperty(Element propertyElement) {
        String propertyName = propertyElement.getAttribute("name");
        String columnName = propertyElement.getAttribute("columnName");
        String dataType = propertyElement.getAttribute("dataType");
        int length = Integer.parseInt(propertyElement.getAttribute("length"));
        int scale = Integer.parseInt(propertyElement.getAttribute("scale"));
        boolean required = Boolean.parseBoolean(propertyElement.getAttribute("required"));
        return new WuProperty(propertyName, columnName, dataType, length, scale, required);
    }

    private static String getTextContent(Element element, String tagName) {
        return element.getElementsByTagName(tagName).item(0).getTextContent();
    }

    public static WuObjectDefinition getObjectDefinition(String packageName, String objectName) {
        if (objectDefinitions.size() == 0) {
            initObjectFactory();
        }
        return objectDefinitions.get(packageName + "." + objectName);
    }

    public static Map<String, WuObjectDefinition>  getWuObjectFactoryMap(){
        return objectDefinitions   ;
    }
}
